package TDengineDB

import (
	"errors"
	"fmt"
	"strconv"
	"sync"
	"time"
)

//索引记录
var (

	mapClient = sync.Map{}
	clientLock sync.Mutex // 连接锁定防止并发访问

	databaseMap = sync.Map{}
	databaseLook sync.Mutex

	tableMap  = sync.Map{}
	tableLook  sync.Mutex
)

//GetTDengineClient 获取客户端
func GetTDengineClient(config map[string]string) *TDengineClient {
	ipport := config["ipport"]
	value, ok := mapClient.Load(ipport)
	if ok {
		return value.(*TDengineClient)
	}
	clientLock.Lock()
	defer clientLock.Unlock()

	username := config["username"]
	password := config["password"]
	timeout := time.Second * 30
	if timeoutStr, ok := config["timeout"]; ok {
		atoi, err := strconv.Atoi(timeoutStr)
		if err == nil {
			timeout = time.Second * time.Duration(atoi)
		}
	}
	retryCount := 3
	if retryCountStr, ok := config["retryCount"]; ok {
		retryCountTmp, err := strconv.Atoi(retryCountStr)
		if err == nil {
			retryCount = retryCountTmp
		}
	}
	client := NewTDengineClient(ipport, username, password, timeout, retryCount)
	return client
}

// DataBaseMapping 添加映射
// @client 连接对象
// @dataName 数据库名
func DataBaseMapping(config map[string]string) *TDengineContent {
	dbname := config["dbname"]
	key := fmt.Sprint(config["ipport"],"@#@",dbname)
	value, ok := databaseMap.Load(key)
	if ok {
		return value.(*TDengineContent)
	}
	databaseLook.Lock()
	defer databaseLook.Unlock()

	value, ok = databaseMap.Load(key)
	if ok {
		return value.(*TDengineContent)
	}
	client := GetTDengineClient(config)
	content := &TDengineContent{
		client:      client,
		database:    dbname,
		config:      config,
	}
	content.createDatabase(config)  //检测创建数据库
	databaseMap.Store(key,content)
	return content
}

//TDengineContent 数据库上下文
type TDengineContent struct {
	client      *TDengineClient   //客户端
	database    string            //数据库名称
	config      map[string]string //配置
}

//createDatabase 创建数据库
func (t *TDengineContent) createDatabase(config map[string]string) error {
	//查看数据库是否存在
	res, err := t.client.Execute(fmt.Sprint("use ", t.database, ";"))
	if err == nil && res.Code == 0 {
		//数据库存在
		return nil
	}
	//获取数据库创建语句
	createDatabase,ok := config["createDatabase"]
	if ok {
		//外部特殊定义
		res, err = t.client.Execute(createDatabase)
	}else {
		keepDay, ok := t.config["keepday"]
		if !ok {
			return errors.New(fmt.Sprint("连接未配置 keepday"))
		}
		precision, ok := t.config["precision"]
		if !ok {
			precision = "ms"
		}
		//默认
		res, err = t.client.Execute(fmt.Sprint("CREATE DATABASE IF NOT EXISTS ", t.database, " KEEP ", keepDay, " PRECISION '", precision,"';"))
	}
	if err != nil {
		return err
	}
	return nil
}

//GetConfig 获取配置
func (t *TDengineContent) GetConfig() map[string]string {
	return t.config
}

//GetDatabase 获取数据库名称
func (t *TDengineContent) GetDatabase() string {
	return t.database
}

//Execute 执行sql
func (t *TDengineContent) Execute(sqlConn string) (*ExecuteResult,error)  {
	return t.client.Execute(sqlConn)
}

//GetTDengineRepository 获取集合仓储
// entity 结构体,columnModel列模型（"Beijng.Chaoyang", 2）
// INSERT INTO d1001 USING METERS TAGS ("Beijng.Chaoyang", 2) VALUES (now, 10.2, 219, 0.32);
func (t *TDengineContent) GetTDengineRepository(entity ITDengineTable) (ITDengineRepository,error) {
	tableName := entity.GetSuperTableName()
	key := fmt.Sprint(t.client.url,"#",t.database, "#", tableName)
	val, ok := tableMap.Load(key)
	if ok {
		return val.(ITDengineRepository), nil
	}
	tableLook.Lock()
	defer tableLook.Unlock()

	val, ok = tableMap.Load(key)
	if ok {
		return val.(ITDengineRepository), nil
	}
	repository := NewTDengineRepository(t.database,tableName,t.client)
	res, err := t.Execute(fmt.Sprint("DESCRIBE  ", t.database, ".", entity.GetSuperTableName(), ";"))
	if err == nil && res.Code == 0 {
		//数据库表存在
		tableMap.Store(key, repository)
		return repository, nil
	}
	tag := entity.GetTagColumn()
	value := entity.GetFieldColumn()
	//直接执行(数据表存在会异常)
	_, err = t.Execute(fmt.Sprint("CREATE STABLE  IF NOT EXISTS ", t.database, ".", tableName, " (", value, ") TAGS (", tag, ");"))
	if err != nil {
		return nil, err
	}
	return repository, nil
}